package small.common.core.spi.extension;

import small.common.core.spi.SpiLoader;
import small.common.core.spi.extension.interceptor.ExtensionLoaderInterceptor;
import small.common.core.util.Holder;
import small.common.core.util.MethodUtil;
import small.common.designPattern.structure.proxy.AdvisedSupport;
import small.common.designPattern.structure.proxy.ProxyFactory;
import small.common.designPattern.structure.proxy.TargetSource;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

import static java.util.stream.StreamSupport.stream;

/**
 * 拓展加载器
 *
 * @author jinzhou
 * @data 2023/4/13 10:56
 */
public class ExtensionLoader<T> {
    /**
     * 拓展加载器集合
     */
    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);

    /**
     * 代理工厂
     */
    private static final ProxyFactory EXTENSION_PROXY_FACTORY = ProxyFactory.INSTANCE;

    /**
     * 拦截器
     */
    private static final ExtensionLoaderInterceptor EXTENSION_LOADER_INTERCEPTOR = new ExtensionLoaderInterceptor();

    /**
     * 加载类
     */
    private final Class<?> type;

    /**
     * 加载目录
     */
    private static volatile List<LoadingStrategy> strategies = loadLoadingStrategies();

    /**
     * 加载器
     */
    private SpiLoader<T> spiLoader;

    /**
     * TODO 待后续拓展自动注入
     * 对象工厂 用于注入
     */
    private final ExtensionFactory objectFactory;


    /**
     * 适配器缓存
     */
    private final Holder<Object> cachedAdaptiveInstance = new Holder<>();

    /**
     * 适配器Class对象
     */
    private volatile Class<?> cachedAdaptiveClass = null;

    /**
     * 创建拓展器异常
     */
    private volatile Throwable createAdaptiveInstanceError;


    /**
     * 获取拓展加载器唯一入口
     *
     * @param type
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type == null");
        }
        //必须是接口
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

    /**
     * 私有化构造方法,控制获取入口
     *
     * @param type
     */
    private ExtensionLoader(Class<T> type) {
        this.type = type;

        String[] directoryArray = strategies.stream()
                .map(LoadingStrategy::directory)
                .toArray(String[]::new);
        //设置加载器
        this.spiLoader = SpiLoader.newInstance(type, directoryArray);

        //设置拓展工厂
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

    /**
     * 获取加载的拓展类名称
     *
     * @return
     */
    public Set<String> getSupportedExtensions() {
        Map<String, Class<?>> clazzes = getExtensionClasses();
        return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
    }

    /**
     * 获取拓展类class对象
     * @return
     */
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> loaderClasses = spiLoader.getLoaderClasses();
        for (Map.Entry<String, Class<?>> entry : loaderClasses.entrySet()) {
            Class<?> clazz = entry.getValue();
            if (clazz.isAnnotationPresent(Adaptive.class)) {
                if (cachedAdaptiveClass == null) {
                    cachedAdaptiveClass = clazz;
                } else if (!cachedAdaptiveClass.equals(clazz)) {
                    throw new IllegalStateException("More than 1 adaptive class found: "
                            + cachedAdaptiveClass.getName()
                            + ", " + clazz.getName());
                }
            }
        }
        if (cachedAdaptiveClass != null){
            spiLoader.removeLoaderClass(cachedAdaptiveClass);
        }
        return loaderClasses;
    }

    /**
     * 获取指定类型加载器
     *
     * @param clazz
     * @return
     */
    public T getExtension(Class<? extends T> clazz) {
        return spiLoader.getInstance(clazz);
    }

    /**
     * 获取指定名称加载器
     *
     * @param name
     * @return
     */
    public T getExtension(String name) {
        return spiLoader.getInstance(name);
    }

    /**
     * 获取所有加载器
     * @param
     * @return
     */
    public List<T> getExtensionList() {
        return spiLoader.getInstanceList();
    }


    /**
     * 获取加载目录
     *
     * @return
     */
    private static List<LoadingStrategy> loadLoadingStrategies() {
        return stream(ServiceLoader.load(LoadingStrategy.class).spliterator(), false)
                .collect(Collectors.toList());
    }


    /**
     * 获取拓展类
     *
     * @return
     */
    public T getAdaptiveExtension() {
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            //避免重复创建失败
            if (createAdaptiveInstanceError != null) {
                throw new IllegalStateException("Failed to create adaptive instance: " +
                        createAdaptiveInstanceError.toString(),
                        createAdaptiveInstanceError);
            }

            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        createAdaptiveInstanceError = t;
                        throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
                    }
                }
            }
        }

        return (T) instance;
    }

    /**
     * 创建拓展器适配器
     *
     * @return
     */
    private T createAdaptiveExtension() {
        try {
            return getAdaptiveExtensionClass();
        } catch (Exception e) {
            throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

    /**
     * 获取拓展器适配器
     *
     * @return
     */
    private T getAdaptiveExtensionClass() throws InstantiationException, IllegalAccessException {
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return (T) cachedAdaptiveClass.newInstance();
        }
        //创建代理类
        return createAdaptiveExtensionClass();
    }

    /**
     * 创建代理类
     *
     * @return
     */
    private T createAdaptiveExtensionClass() {
        //查询方法上是否有@Adaptive注解
        if (!MethodUtil.hasAdaptiveMethod(type.getMethods(), Adaptive.class)) {
            throw new IllegalStateException("No "+Adaptive.class.getTypeName()+" exist on extension: " + type.getName() + "method , refuse to create the adaptive class!");
        }
        T proxy = EXTENSION_PROXY_FACTORY.getProxy(new AdvisedSupport<T>(new TargetSource<T>(type), EXTENSION_LOADER_INTERCEPTOR));

        return proxy ;
    }

    @Override
    public String toString() {
        return this.getClass().getName() + "[" + type.getName() + "]";
    }

}
